// =================================================================================================
// Copyright 2012 Twitter, Inc.
// -------------------------------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this work except in compliance with the License.
// You may obtain a copy of the License in the LICENSE file, or at:
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =================================================================================================

package com.twitter.common.logging.log4j;

import com.google.common.collect.ImmutableMap;

import org.apache.log4j.Layout;
import org.apache.log4j.Level;
import org.apache.log4j.spi.LocationInfo;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.ThrowableInformation;

import com.twitter.common.logging.Glog;
import com.twitter.common.logging.Glog.Formatter;

/**
 * Log4j Layout to match the format generated by glog.
 *
 * @see Glog
 */
public class GlogLayout extends Layout implements Formatter<LoggingEvent> {

  private static final ImmutableMap<Level, Glog.Level> LEVEL_LABELS =
      ImmutableMap.<Level, Glog.Level>builder()
          .put(Level.TRACE, Glog.Level.DEBUG)
          .put(Level.DEBUG, Glog.Level.DEBUG)
          .put(Level.INFO, Glog.Level.INFO)
          .put(Level.WARN, Glog.Level.WARNING)
          .put(Level.ERROR, Glog.Level.ERROR)
          .put(Level.FATAL, Glog.Level.FATAL)
          .build();

  @Override
  public String format(LoggingEvent record) {
    return Glog.formatRecord(this, record);
  }

  @Override
  public boolean ignoresThrowable() {
    return false; // We handle stack trace formatting.
  }

  @Override
  public void activateOptions() {
    // We use no options
  }

  @Override
  public String getMessage(LoggingEvent record) {
    return record.getRenderedMessage();
  }

  @Override
  public String getClassName(LoggingEvent record) {
    LocationInfo locationInformation = record.getLocationInformation();
    return (locationInformation != null)
        ? locationInformation.getClassName()
        : null;
  }

  @Override
  public String getMethodName(LoggingEvent record) {
    LocationInfo locationInformation = record.getLocationInformation();
    return (locationInformation != null)
        ? record.getLocationInformation().getMethodName()
        : null;
  }

  @Override
  public Glog.Level getLevel(LoggingEvent record) {
    return LEVEL_LABELS.get(record.getLevel());
  }

  @Override
  public long getTimeStamp(LoggingEvent record) {
    return record.getTimeStamp();
  }

  @Override
  public long getThreadId(LoggingEvent record) {
    return Thread.currentThread().getId();
  }

  @Override
  public Throwable getThrowable(LoggingEvent record) {
    ThrowableInformation throwableInformation = record.getThrowableInformation();
    return throwableInformation != null ? throwableInformation.getThrowable() : null;
  }
}
